哈囉大家好~
不知道昨天的進度條做的怎麼樣?
想要交作業的人可以貼在昨天的留言區給我呦!
那我們今天的內容也很簡單,
二話不說,要開始囉?
跟昨天的環境相同,兔兔為了寫文章方便是重新建立了一個,你們可以重新建立新的專案從頭練習一次,也可以在昨天做完的專案直接多增加新的元件哦!
和昨天一樣,先建立空白元件,所以在專案裡的 ./src/components
資料夾中新增一個 RabbitButton.vue
的元件:
完成後,增添以下內容:
<template>
</template>
<script>
export default {
name: "RabbitButton",
}
</script>
接著我們就可以把這個元件新增到畫面中,打開 App.vue
然後內容跟昨天差不多:
<template>
<div :class="[
'w-screen h-screen',
'flex flex-col',
'justify-center items-center',
'gap-5',
]"
>
<RabbitButton />
</div>
</template>
<script>
import RabbitButton from './components/RabbitButton.vue'
export default {
data() {
return {
}
},
components: {
RabbitButton,
}
}
</script>
這樣準備工作大妥當,開始按鈕博物館導覽啦!
按鈕的要素其實很簡單,不外乎就是一個中間有字的矩形,滑鼠懸停時有顏色變化,最好的話連按下後也有相對應的效果,才是一個良好的互動。
那麼基於這些要素,我們就可以這麼做:
px-6
、py-3
rounded-md
、font-bold
bg-gray-400
、hover:bg-gray-300
、active:bg-gray-500
hover:scale-105
、active:scale-95
transition-all
按鈕
二字讓它不會被誤認吧?所以綜合起來,就會像是這樣:
<template>
<div
:class="[
'px-6 py-3',
'rounded-md font-bold',
'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
'hover:scale-105 active:scale-95',
'transition-all'
]"
>
按鈕
</div>
</template>
<script>
export default {
name: "RabbitButton",
}
</script>
這麼快就有 fu 了嗎?
哎呀後面還有更有趣的啦!
畢竟我們現在按鈕還非常的單調,
讓我們來幫它點綴一下!
Yes,這麼快就來到了我們動起來的環節了。
別以為會這麼輕易地結束,
我們現在看到的按鈕是這個樣子:
可是兔兔期待的是這個樣子:
哇,還是有點落差對吧?
「摁,是沒錯啦,但不就是差個 icon 和顏色而已嘛 ... 不過每次插入 svg 的 icon 都會覺得把結構弄得好雜亂 ...」
嘿嘿,這個立馬幫你解決!
沒錯,這就是輪到不知道甚麼時候才能派上用場但現在就派上用場的 Slot 啦!
slot 可以把原本一直要替換的東西從內部解藕出來,那麼一來我們在外面替換時就不用一直修改元件的內部功能了~
現在在文字前後幫按鈕加上兩個 slot,分別取名為 iconLeft
和 iconRight
,然後因為想要 icon 和文字可以橫向排列且之間有點空隙,我們順便加上 flex gap-2
的樣式:
<!-- RabbitButton.vue -->
<div
:class="[
'flex gap-2',
'px-6 py-3',
'rounded-md font-bold',
'text-white',
'bg-blue-400 hover:bg-blue-300 active:bg-blue-500',
'hover:scale-105 active:scale-95',
'transition-all'
]"
>
<slot name="iconLeft" />
按鈕
<slot name="iconRight" />
</div>
這麼一來就可以輕鬆的在按鈕文字的前或後加上 icon 啦!
然後啊,Tailwind 官方的專案中有個特別的網站,叫做 heroicons
,雖然裡面的 icon 量真的不多,但是各個都是精心設計過,適合搭配 Tailwind 直接使用的 icon,還可以直接複製 svg,算是很方便啦~
我們回到 App.vue
,兔兔這邊要用的 icon 就是在 heroicons 上面找的 wifi
icon (不是 wife,要認明。),然後包在指定 iconLeft 插槽
的 template 中:
<!-- App.vue -->
<div
:class="[
'w-screen h-screen',
'flex flex-col',
'justify-center items-center',
'gap-5',
]"
>
<RabbitButton>
<template v-slot:iconLeft>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
</svg>
</template>
</RabbitButton>
</div>
讚啦,這樣真的很方便,把 icon 從元件中抽離之後就可以隨時替換了!
可是 ...(你這兔又來了,果然不管做的怎麼樣都有話要說!)
就是真的需要提出來啦!
按鈕的文字和顏色的改變的確是還不方便,所以我們就必須用到 ...
對,就是 Props。
我們剛剛說到要改變文字和顏色,所以就幫 props 增加兩個內容,但這兩個內容都必須要有預設值:
<script>
export default {
name: "RabbitButton",
props:{
text: {
default: "按鈕"
},
color: {
default: "gray"
},
},
}
</script>
我們先來解決按鈕文字的部分,把按鈕
的字樣取代成 {{ text }}
:
<div
:class="[
'flex gap-2',
'px-6 py-3',
'rounded-md font-bold',
'text-white',
'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
'hover:scale-105 active:scale-95',
'transition-all'
]"
>
<slot name="iconLeft" />
{{ text }}
<slot name="iconRight" />
</div>
再來,就要解釋到為什麼 color 要有預設值且預設值是字串了。 因為我們要利用物件 (字典) 的特性來快速的切換按鈕的色系!
為了方便監控和節省資源,我們先在 computed 中建立一個 colorSelector 函數,並返回一個空白物件。
<script>
export default {
name: "RabbitButton",
props:{
text: {
default: "按鈕"
},
color: {
default: "gray"
},
},
computed: {
colorSelector() {
return {}
}
}
}
</script>
建立好之後,我們把元件中顏色的那一行 tailwind 語法加到物件中並命名為 gray
,且在物件後加上 [this.color]
來讓函數找到並返回指定名稱為 gray
的內容:
<script>
export default {
name: "RabbitButton",
props:{
text: {
default: "按鈕"
},
color: {
default: "gray"
},
},
computed: {
colorSelector() {
return {
gray: 'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
}[this.color]
}
}
}
</script>
然後把 colorSelector 函數加回 class 列表,並測試一次:
<div
:class="[
'flex gap-2',
'px-6 py-3',
'rounded-md font-bold',
'text-white',
colorSelector,
'hover:scale-105 active:scale-95',
'transition-all'
]"
>
<slot name="iconLeft" />
{{ text }}
<slot name="iconRight" />
</div>
看起來沒什麼變化是正常的,但至少這表示沒寫錯!
打鐵要趁熱,我們接著來追加其他顏色吧~
最後追加完,完整的 code 可能會是這個樣子:
<template>
<div
:class="[
'flex gap-2',
'px-6 py-3',
'rounded-md font-bold',
'text-white',
colorSelector,
'hover:scale-105 active:scale-95',
'transition-all'
]"
>
<slot name="iconLeft" />
{{ text }}
<slot name="iconRight" />
</div>
</template>
<script>
export default {
name: "RabbitButton",
props:{
text: {
default: "按鈕"
},
color: {
default: "gray"
},
},
computed: {
colorSelector() {
return {
gray: 'bg-gray-400 hover:bg-gray-300 active:bg-gray-500',
green: 'bg-green-400 hover:bg-green-300 active:bg-green-500',
blue: 'bg-blue-400 hover:bg-blue-300 active:bg-blue-500',
red: 'bg-red-400 hover:bg-red-300 active:bg-red-500',
yellow: 'bg-yellow-400 hover:bg-yellow-300 active:bg-yellow-500',
}[this.color]
}
}
}
</script>
然後這邊值得注意的是,為什麼不用變數取代 bg-XXX-400
、hover:bg-XXX-300
就好了呢? 為何還要這樣大費周章地去把 class 名稱都寫過一遍?
因為要讓 purge 讀取
到要編譯的 class 的話,class 名稱
必須保持完整
,不能被拆開!
所以為了要讓樣式能正確被讀取到且被編譯,不能使用 "bg-" + color + "500"
或是 "opacity-" + number
這種組合過的形式,這對 Tailwind 來說是不合法的 class 名稱哦。
既然完成了,我們就快點來測試吧!
好興奮啊!
最後的測試環境,我們來做三個按鈕吧!
然後為了美化中的美化,我們可以在按鈕元件中加上 cursor-pointer
讓它看起來更像樣!
第一個按鈕,就是最普通的按鈕啦!
<RabbitButton />
再來是讓人看起來很連網路的 wifi 按鈕!
<RabbitButton text="wifi" color="blue">
<template v-slot:iconLeft>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.111 16.404a5.5 5.5 0 017.778 0M12 20h.01m-7.08-7.071c3.904-3.905 10.236-3.905 14.141 0M1.394 9.393c5.857-5.857 15.355-5.857 21.213 0" />
</svg>
</template>
</RabbitButton>
最後,是安裝軟體時會出現的下一步
按鈕~
<RabbitButton text="下一步" color="green">
<template v-slot:iconRight>
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
</svg>
</template>
</RabbitButton>
OK,超成功的啦!
今天是不是也很輕鬆簡單啊?
兔兔覺得這樣做按鈕又美、彈性又高!
以後遇到再多狀況也只要小修改就能夠繼續使用了,
這有再度登場的機會正是做元件的目的!
希望你們都能夠試試看,如果有更好方法或建議 ...
做成作業留言給我看嘿!!!!
關於兔兔們:
( # 兔兔小聲說 )
不是兔兔偷懶,兔兔只是陪富堅去取材。